/**
 * @Copyright (c) 2005,闲情网站
 * @All rights reserved.
 *
 * Ajax 应用类
 *
 * @file_name   DAjax.js
 * @version     2.0
 * @author      黄新泽
 * @create      2005-05-06
 * @update      2007-09-27 14:45:42
 */

/**
 * Class and Function List:
 * Function list:
 * - initialize(path, requestLogic, queryKey, setResponseKey)
 * - complete(transport)
 * - setResponseData(transport)
 * - setResponseCtl(ctlName, fldName)
 * - formSerialize()
 * - sendRequest(q)
 * - rand()
 * - isSet(arg)
 * - isTrue(v)
 * Classes list:
 * - DAjax
 */
/**
 *	var logic = {ajaxId:"user_data", act:"findUserRp",  type:"o", cla:"UserRp:username", operateType:"class"};
 *	var ctl = ['username', 'pass'];
 *
 *	var user = new DAjax({url:"../gateway/user_info.php", message:"读取用户信息...", onSuccess:onSuccess }, logic, {}, ctl);
 *
 */


var	DAjax =	Class.create();
DAjax.prototype	= 
{
	className : 'DAjax',
	lbType : 'n',
	debug	: true,
	request:{num:0},


	/**
	 * 构造函数
	 *
	 * @param Object	path				ajax request url/msg
	 * @param Object	option				option
	 * @param Object	requestLogic	contain 'ajaxId act type'
	 * @param Array		queryKey			query key
	 * @param Array or Object	setResponseKey	ctl set key
	 *
	 * TODO:更改后为option:{ option, requestLogic, queryKey, setResponseKey}
	 * @access	public 
	 */
	initialize : function(url, option) 
	{
		this.url				= null;
		this.eTarget			= null;
		this.option				= {formName: null, method:"post", messageState:true, message:"服务通信中,请稍候...", page:null,  lbType:"n"};
		this.requestLogic		= {ajaxId: '_' + this.rand(), act:"d", type:"o", cache:false};
		this.queryKey			= null;			//数组，传递给后台的要查询的字段，
		this.setResponseKey		= null;			//数组或者是关联数组，得到返回的数据后，要设置数据的客户端控件

		this.url	= url;
		Object.extend(this.option, option ? option.option : {});
		Object.extend(this.requestLogic, option ? option.logic : {});
		this.queryKey = option ? option.queryKey : {};
		this.setResponseKey = option ? option.setResponseKey : {};

		this.queryString = $H(this.requestLogic).toQueryString();
		this.eTarget	 = this.requestLogic.ajaxId;

		//关联数组，多记录，要传送的查询的数据,数据要在真正查询的时候才能被正确设置
		this.queryData				= {}						;	
		this.responseRows			= 0							;	//返回查询数据的行数
		this.error					= 0							;	//返回是否有误

		this.setResponseRowKey		= new Array()				;	//数组或者是关联数组，得到返回的数据后，要设置表格数据的客户端控件

		this.onBeforeSend			= function(){this.sendRequestMark = true	; return true;}	;	//发送前和的方法，比如把按钮隐藏起来
		this.onAfterGet				= function(){}				;	//得到数据后执行的方法,不管是否为正确数据!
		this.onComplete				= function(){}				;	//设置数据后执行的方法
		this.onNoneGet				= function(){}				;	//设置未取到值所要执行的方法
		this.collectCarbage			= function(){
			if (Prototype.Browser.IE)
			{
				CollectGarbage(); 
				setTimeout("CollectGarbage();", 1);
			}
		};	

		//初始化提示消息类
		this.messageId				= this.requestLogic.ajaxId + this.rand();	//提示消息ID
		this.msg					= new Message(this.messageId, this.option.message, this.option.messageState);
		

		if(this.isTrue(this.option.page))
		{
			this.page = new Page(this.option.page);
		}

		this.lbType = this.option.lbType;

		//Cache
		if('undefined'!=typeof(Cache) && this.requestLogic.cache)
		{
			this.cache = new Cache(this.requestLogic.ajaxId, this.requestLogic.cache);
		}
		else
		{
			this.cache = false;
		}

	},

	/**
	 * 完成状态方法
	 *
	 * @param Object	transport	ajax response object
	 *
	 * @access	public
	 */
	complete : function(transport)
	{
		if (transport.readyState ==	4) 
		{
			this.request.num--;

			var	status = 0;

			try
			{
				status = transport.status;
			}
			catch(e)
			{
			}

			if (200	!= status) 
			{
				if (this.debug)
				{
					if (status > 10000 || !status)
					{
						//mask.showMsgBox('与服务器通信超时, 请重试! ' + status + ' <br />\n', true);
					}
					else if (status == 499)
					{
						mask.showMsgBox('发生错误!<br />你的卡巴斯基杀毒软件可能运行于家长控制模式下.<br />请修改卡巴斯基:设置->保护->家长控制, 取消家长控制!<br />' , true);
					}
					else if (status < 400)
					{
						
					}
					else
					{
						mask.showMsgBox('与服务器通信超时, 请重试: ' + status + ' <br />\n' , true);
						//transport.responseText.stripTags()
					}
					
				}
				
				this.msg.failure();
			}
		}
	},
	

	/**
	 * 异常处理
	 *
	 * @param Object	transport	ajax response object
	 *
	 * @access	public
	 */
	exception : function(transport, e)
	{
//		var line = 0;
//
//		if (Prototype.Browser.IE)
//		{
//			line = ' 错误类型 : ' + (e.number & 0xFFFF); 
//		}
//		else
//		{
//			line = ' 错误行数 : ' + e.lineNumber;
//		}
//
//		mask.showMsgBox( '发生异常错误, 请将如下内容发送给我们, 谢谢! <br />' + transport.body + '<br />\n 错误位置 : ' + currentTabId + '<br />\n' + line + '<br />\n 错误消息 : ' + e.message , true);
//
//		this.msg.failure();
	},


	/**
	 * 接收数据句柄
	 *
	 * @param Object	transport	ajax response object
	 *
	 * @access	public
	 */
	receiveData : function(transport)
	{
		try
		{
			Element.hide('tooltip_singleton');
		}
		catch(e)
		{
		}

		var	status = 0;

		try
		{
			status = transport.status;
		}
		catch(e)
		{
		}

		if (200	== status) 
		{
			//增加扩展性...... demo  arg 可以通过一个变量来传递,parameters 后来合并,变可以完全兼容
			if (isSet(this.option.onSuccess))
			{
				this.option.onSuccess(transport, this);
			}
			else
			{
				this.setResponseData(transport, this);	
			}

			//Cache
			if(this.cache)
			{
				if (!this.cache.getCache(this.cache.key))
				{
					this.cache.updateCache(this.cache.key, transport);
					return false;
				}

			}
		}
	},

	/**
	 * 响应方法, 设置各种数据
	 *
	 * @param Object	transport	ajax response object
	 *
	 * @access	public
	 */
	setResponseData : function(transport, self) 
	{
		//这里要执行onAfterGet事件
		this.onAfterGet()	;
		var	responseText = transport.responseText;

		//直接返回HTML数据,这样屏蔽了下面的处理数据,返回格式简单
		if ("e" == this.requestLogic.type)
		{
			this.responseData = responseText;

			try
			{
				if ('undefined' != typeof(mask))
				{
					mask.deEvent(this.eTarget);
				}

				$(this.eTarget).update(responseText);

				if ('city_out'==this.eTarget || 'city_in'==this.eTarget)
				{
				}
				else
				{
					if('undefined'!=typeof(Element.lazyload)  && $(this.eTarget))
					{
						//$$('#' + this.eTarget + ' img').invoke('lazyload');
					}
				}

				if ('undefined' != typeof(mask))
				{
					mask.actions(this.eTarget);
				}
				
			}
			catch(e)
			{
			}
			

			if (true)
			{
				this.onComplete(responseText);
			}
			else
			{
				this.onNoneGet();
			}

			if (Prototype.Browser.IE && !Prototype.Browser.IE7) // && !Prototype.Browser.IE7
			{
			}

			responseText = null;
			this.msg.removeMessage();			
			return false;
		}

		var	data = null;

		try
		{
			data = responseText.evalJSON();
		}
		catch(e)
		{
			if (this.option.messageState)
			{
				if (responseText.blank())
				{
					responseText = '发生错误!';
				}
				mask.showMsgBox(responseText, true);
				this.msg.removeMessage();
			}
		}

		responseText = null;

		if (data)
		{
			this.responseMessageData	= data[0] || {num:0, error:1}	; 
			this.responseRows			= parseInt(this.responseMessageData.num);
			this.error					= parseInt(this.responseMessageData.error);
			this.responseData			= data[1] ? data[1] : {}; 

			this.rMsg					=	this.responseMessageData.message;

			//if ($('debug') && data[2])
			if ('undefined' != typeof(data[2]))
			{
				console.debug(data[2]);
				//new Insertion.Bottom($('debug'),  '<br />\n' + data[2]);
			}
			

			//被上面屏蔽掉,暂时不使用
			if ("e" == this.responseMessageData.type)
			{
				$(this.responseMessageData.id).innerHTML = this.responseData;

				if (this.responseRows)
				{
					this.onComplete();
				}
				else
				{
					this.onNoneGet();
				}

				this.msg.removeMessage();
				this.collectCarbage();
				return false;
			}

			if(this.isTrue(this.error))
			{
				this.errorMessage =	this.responseMessageData.message;
				//这里执行onNoneGet
				
				//this.msg.failure();
				this.msg.removeMessage();
				this.onNoneGet();
				data = null;
				this.responseData = null;
				this.collectCarbage();
				return;
			}
			else
			{
				//检测是否需要自动设置客户端控件, 暂时只处理一行的
				if(this.isTrue(this.setResponseKey))
				{
					var	i, ctlName, fldName;

					//如果是数组，而不是关联数组
					if (window.Array == this.setResponseKey.constructor)
					{
						var l = this.setResponseKey.length;
						for	(i=0; i<l; i++)
						{
							ctlName = this.setResponseKey[i] ;
							fldName = ctlName ;
							
							this.setResponseCtl(ctlName, fldName);
						}//end for
					}
					else if(window.Object == this.setResponseKey.constructor)
					{
						for	(i in this.setResponseKey )
						{
							ctlName = i ;
							fldName = this.setResponseKey[i]  ;
							
							this.setResponseCtl(ctlName, fldName);
						}//end for

					}
					else
					{
						alert('setResponseKey Wrong!');
					}
				}

				//执行onComplete
				this.onComplete(data);
			}
		}


		this.msg.removeMessage();	
		data = null;
		this.responseData = null;
		this.collectCarbage();
	},

	/**
	 * 设置控件数据
	 *
	 * @param String	ctlName	control name 
	 * @param String	fldName	control value: always is db field name 
	 *
	 * @access	public
	 */
	setResponseCtl : function(ctlName, fldName)
	{
		//存放某个控件对象
		var ctl = $(ctlName) ;

		var	keyData	=	this.responseData[0] ;
		if(!ctl)
		{
			//alert("无法找到控件 : " + ctlName);
			return	false;
		}

		try 
		{
			if(typeof(keyData[fldName]) === "undefined")
			{
				alert("无法取得该字段的数据:"+fldName);
				return	false;
			}
			else
			{
				ctl.value = keyData[fldName]; 
			}

		}
		catch(e)
		{
			alert(e.message);
		}
	},

	/**
	 * 序列化表单数据
	 *
	 * @return	String	Serialize data
	 *
	 * @access	public
	 */
	formSerialize : function()
	{
		return this.option.formName ? '&' + Form.serialize(this.option.formName) : '';
	},

	/**
	 * 发送Ajax请求
	 *
	 * @param	Object	q	query data
	 *
	 * @access	public
	 */
	sendRequest : function(ctl, q) 
	{
		//如果一段时间后用户没有操作页面,则停止发送ajax请求
		if ('undefined' != typeof(active))
		{
			if (!active)
			{
				return false;
			}
		}
		//cache不支持并发处理,解决办法,传回key值.用到较少,不做处理
		//为了cache考虑,禁止统一操作并发请求
		if (this.cache && this.msg.loadCount)
		{
			//alert(this.msg.loadMessage + "\n 请稍候再次读取!");
			return false;
		}


		if (this.request.num >= 9)
		{
			console.info('发送请求太多.');
			return ;
		}
		//执行onBeforeSend事件
		this.onBeforeSend();

		var	tQS	= this.queryString;
		tQS	+= this.formSerialize();

		if (this.isSet(ctl))
		{
			ctl.each(function(s) 
					{
						if(!$(s))
						{
							//alert("无法找到控件 : " + s);
						}
						else
						{
							tQS	+= "&" + Form.Element.serialize(s);
						}
					});
		}

		if (this.isSet(q))
		{
			tQS	+= '&' + $H(q).toQueryString();
		}
		
		var	qDS	= $H(this.queryData).toQueryString();
		tQS	+= qDS ? '&' + qDS : '';



		if(!this.sendRequestMark)
		{
			return false;
		}

		//Cache
		if(this.cache)
		{
			this.cache.key = tQS.replace(/[^a-zA-Z0-9]/gi,"");

			if (this.cache.getCache(this.cache.key))
			{
				this.receiveData(this.cache.getCache(this.cache.key));
				return false;
			}
		}

		//设置随机数
		var	s =	this.rand();
		tQS	+= '&r=' + s ;

		this.msg.showMessage();

		this.request.num++;

		if ('e'	== this.requestLogic.type)
		{

				//已经更新了
//				var	ajaxObj	= new Ajax.Updater(
//												this.requestLogic.ajaxId,
//												this.url,
//												{
//													method: this.option.method,
//													requestHeaders:["Cache-Control","no-cache"],
//													parameters:	tQS,
//
//													onSuccess: this.receiveData.bind(this),
//													onComplete:this.complete.bind(this)
//												}
//												);	
				var	ajaxObj	= new Ajax.Request(
												this.url,
												{
													method: this.option.method,
													requestHeaders:["Cache-Control","no-cache"],
													parameters:	tQS,

													onSuccess: this.receiveData.bind(this),
													onComplete		:this.complete.bind(this),
													onException		:this.exception.bind(this)

												}
												);	
		}
		else
		{
				var	ajaxObj	= new Ajax.Request(
												this.url,
												{
													method: this.option.method,
													requestHeaders:["Cache-Control","no-cache"],
													parameters:	tQS,

													onSuccess: this.receiveData.bind(this),
													onComplete		:this.complete.bind(this),
													onException		:this.exception.bind(this)

												}
												);	
		}
		
		ctl	= null;
		q	= null;
		qDS = null;
		s	= null;
		tQS = null;
		ajaxObj = null;
	},

	/**
	 * 随机数  public function  暂时放在这儿,跟随此类到处跑
	 *
	 * @return	Int	num rand number
	 *
	 * @access	public
	 */
	rand : function()
	{
		var	today =	new	Date();
		var	num		=	today.getTime();
		return num;	
	},

	/**
	 * isSet -> from PHP  function  public function  暂时放在这儿,跟随此类到处跑
	 *
	 * @return	Mixed	arg Arg need be checked
	 *
	 * @access	public
	 */
	isSet : function(arg)
	{
		return 'undefined' != typeof(arg) ?	true : false;
	},

	/**
	 * function  public function  暂时放在这儿,跟随此类到处跑
	 *
	 * @return	Mixed	arg Arg need be checked
	 *
	 * @access	public
	 */
	isTrue : function(v)
	{
		return (v==true 
			|| ("number"==typeof(v) && 0!=v) 
			|| ("string"==typeof(v) && ""!=v  && "0"!=v && "off"!=v && "no"!=v) 
			|| ("object"==typeof(v) && null!=v && {}!=v && []!=v) 
			);
	}
};